package com.ayoldi.podcastusbsync.downloader;

import java.io.File;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;


import org.apache.log4j.Logger;
import org.joda.time.DateTime;

import com.ayoldi.podcastusbsync.configurator.ConfigurationManager;
import com.ayoldi.podcastusbsync.configurator.ConfigurationUtils;
import com.ayoldi.podcastusbsync.model.Configuration;
import com.ayoldi.podcastusbsync.model.Configuration.UsbDeviceConfiguration.PodcastFeed;
import com.sun.syndication.feed.synd.SyndEnclosure;
import com.sun.syndication.feed.synd.SyndEnclosureImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;

public class FeedsDownloaderThread extends Thread{

	static Logger LOG = Logger.getLogger(FeedsDownloaderThread.class);
	
	private static final int FIRST_TIME_DOWNLOAD_FEEDS=10;

	public static final String CHECK_MODE_PUB_DATE="publishedDate";
	public static final String CHECK_MODE_DOWNLOADS_LOG="downloadsLog";

	private static final String CHECK_MODE=CHECK_MODE_DOWNLOADS_LOG;
	
	
	ConfigurationManager configManager;
	long feedMonitorPeriod;
	
	boolean stopped=false;
	
	public boolean isStopped() {
		return stopped;
	}

	public void setStopped(boolean stopped) {
		this.stopped = stopped;
	}



	public static final String[] ALLOWED_EXTENSIONS=new String[]{"wav","mp3"};
	
	public FeedsDownloaderThread (ConfigurationManager configManager,long feedMonitorPeriod){
		this.configManager=configManager;
		this.feedMonitorPeriod=feedMonitorPeriod;
	}
	
	public void run() {
		
		while (true){			
			
			if (stopped){
				break;
			}
			try {
				downloadNewFeeds();
			}
			catch (Exception e){
				continue;
			}
			synchronized(this) {
                try {
                    this.wait(feedMonitorPeriod);  // wait 5s and check if stopped
                }
                catch(InterruptedException ie){}
            }
		}
		
	}
	
	private void downloadNewFeeds(){
	
		LOG.info("Updating feeds...");
		
		for (PodcastFeed feed : configManager.getFeeds() ){
			if (stopped){
				break;
			}
			LOG.info("Updating feed: "+feed.getName());
			updateFeed(feed,CHECK_MODE);			
		}		
		
	}
	
	private void updateFeed(PodcastFeed feed, String checkMode){
		URL url;

		DateTime newLastCheckedDateTime;		
		boolean allDownloadsSuccessful=false;		
		
		URLConnection conn=null;
		try {
			LOG.debug("Reading feed url: "+feed.getUrl());
			
			url = new URL(feed.getUrl());
			conn=url.openConnection();
			conn.setConnectTimeout(60000);
			conn.setReadTimeout(120000);
			
	        SyndFeedInput input = new SyndFeedInput();
	        SyndFeed feedInternal = input.build(new XmlReader(conn));
	        	        
			List<SyndEntry> feedEntries=feedInternal.getEntries();
			List<SyndEntry> feedEntriesToDownload=new ArrayList<SyndEntry>();
			
			if (feed.getLastChecked()!=null){				
				LOG.info("Feed last checked on: "+feed.getLastChecked());
				for (SyndEntry entry : feedEntries) {
					if (FeedsDownloaderUtils.isNewEntry(entry,checkMode,feed, configManager)){
						feedEntriesToDownload.add(entry);
					}					
					
				}				
				
			}
			else{
				LOG.info("Feed never checked before, getting the last "+FIRST_TIME_DOWNLOAD_FEEDS+" entries.");
				Collections.sort(feedEntries, new FeedPubDateComparator());
				feedEntriesToDownload.addAll(feedEntries.subList(0, FIRST_TIME_DOWNLOAD_FEEDS));
			}
			
			feedEntriesToDownload=FeedsDownloaderUtils.filterListByFeedRegexp(feedEntriesToDownload, feed);
			
			newLastCheckedDateTime=new DateTime();
			allDownloadsSuccessful=downloadEntries(feedEntriesToDownload, configManager.getAbsoluteFeedDownloadFolder(feed.getFolder()),feed.getRenameRule(),feed.getRegex());
			
		} catch (Exception e) {
			e.printStackTrace();
			return;
		} 
		finally{
			if (conn!=null){
				// TODO RELEASE CONNECTION
			}
		}
		
		if (allDownloadsSuccessful){
			boolean feedUpdateTagSuccesfullyUdated=configManager.updateLastCheckedTag(newLastCheckedDateTime,feed);		

		}
		
	}
	
	private boolean downloadEntries(List<SyndEntry> feedEntriesToDownload, File path, String regexRenameRule, String titleFilterRegex) {
		LOG.info("Downloading "+feedEntriesToDownload.size()+" entries to "+path.getAbsolutePath());
		boolean success=true;
		for (SyndEntry entry : feedEntriesToDownload){
			
			if (stopped){
				break;
			}
			
			DownloadsLog downloadsLog = new DownloadsLog(path);
			
			try {			
				
				URL downloadURL=FeedsDownloaderUtils.getURLToDownloadFromEntry(entry);
				if (downloadURL==null){
					continue;
				}
				
				LOG.info("Downloading "+entry.getTitle());
				boolean fileSuccess=FeedsDownloaderUtils.downloadFile(downloadURL,path,false,FeedsDownloaderUtils.getFileNameFromTitle(entry.getTitle(), regexRenameRule,titleFilterRegex));
				if (!fileSuccess){
					success=false;
				}
				else{
					downloadsLog.addNewDownloadedUrl(downloadURL.toString());
				}
			} catch (Exception e) {
				e.printStackTrace();
				success=false;
				continue;
			}
		}
		return success;
		
	}



	private static class FeedPubDateComparator implements Comparator{

		public int compare(Object o1, Object o2) {
			if (!o1.getClass().equals(SyndEntry.class) || !o2.getClass().equals(SyndEntry.class)){
				return 0;
			}
			
			Date date1=((SyndEntry)o1).getPublishedDate();
			Date date2=((SyndEntry)o2).getPublishedDate();			
			
			long n1 = date1.getTime();
	        long n2 = date2.getTime();
	        if (n1 < n2) return -1;
	        else if (n1 > n2) return 1;
	        else return 0;
		}
		
	}
	
}
